React - 4 Redux高级

UI组件和容器组件无状态组件

  • 普通组件:
  • UI组件:UI负责渲染
  • 容器组件:负责逻辑
  • 无状态组件:当普通组件只有render函数的时候,可以使用无状态组件替换该组件。
    • 普通组件的性能比不上无状态组件的性能高 。无状态组件就是一个函数;普通组件是JS的类,类生成的对象里面还有生命周期函数,执行的时候既要执行函数,又要执行render。
    • 如何使用:一般UI组件只负责页面渲染,不负责逻辑,可以定义为一个无状态组件

ajax数据请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';

// 设置模拟调试器实例
const mock = new MockAdapter(axios);
mock.onGet('/list.json').reply(200, {
list:["iris","jay","gd"]
});
//生命周期函数 mount完成时
componentDidMount(){
axios.get('/list.json').then((res)=>{
// 获取模拟调试器上的mock本地数据
const data =res.data.list;
// 创建ation,传入data;将action传给store
const action = initListAction(data);
console.log(action);
store.dispatch(action);
})
}

Redux-thunk中间件实现ajax数据请求

配置Redux-thunk:同时使用两个中间件:thunk+devtools(调试工具)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//使得store既支持window下的devtools,调式stor;同时引入了Redux-thunk
//高级配置:若存在该方法,则调用,否则使得其为一个compose函数
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
}) : compose;
// 上述的变量存储一下,顺便将中间件[redux]通过applyMiddleware执行一下,传入进去
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);

const store = createStore(reducer,
enhancer
// applyMiddleware(thunk)
);

把异步操作的代码从组件中移除,移除到action中去。之前actionCreator 里面的任意一个creator一个都是函数,该函数返回的内容是一个对象。

使用redux-thunk后,你的action可以是一个函数了。正常来说是return一个对象,使用redux-thunk后,return的结果可以为一个函数函数中可以做异步操作

使用redux-thunk后,action不仅可以是一个action对象(JS对象)了,还可以是一个函数。

构建了一个action,为一个函数,调用dispatch,该action会被自动执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ./store/actionCreator.JS
// 构建了一个action,返回函数,函数的参数是dispatch,函数内进行异步操作,获取ajax请求,创建action,dispatch action到store,更新store
export const getTodoList = () => {
//return一个函数,在函数中执行异步ajax操作
return (dispatch) => {
axios.get('/list.json').then((res)=>{
// 获取模拟调试器上的mock本地数据
const data =res.data.list;
// 创建ation,传入data;将action传给store
const action = initListAction(data);
dispatch(action);
})
}
}

// TodoList.js
// 生命周期函数内,创建action函数,dispatch后执行该函数
componentDidMount(){
const action = getTodoList();
store.dispatch(action);
}

原因:

把异步函数放在生命周期函数中去做,该生命周期函数会越来越复杂且多,组件会越来越大。

好处1:应该把复杂的业务逻辑和异步函数拆分到一个地方去管理。借助redux-thunk,放在actionCreator去管理。

好处2:放在actionCreator的时候,自动化测试时,测试getTodoList方法,比测试生命周期函数要简单的多。

Redux中间件

image-20190419101024985

action和store之间。

对store的dispatch方法的封装、升级。根据参数不同,执行不同的操作。

  • 原始:接收对象后,将对象直接传递给store。
  • 升级后:传递对象和之前一样;传递函数,不会直接传递,而是先执行,执行完后,若需要调用store,该函数内再调用store。
  • 例子:
    • redux-logger中间件,在传递过程中,将action打印。
    • redux-thunk异步问题:将异步放在actionCreator中
    • redux-saga异步问题:将异步单独放在文件中

✨使用React-Redux重写TodoList

安装:yarn add react-redux

提供:

Provider组件:核心组件,把store提供给每一个内部组件,也叫提供器

1
2
3
4
5
6
7
8
9
10
11
12
import { Provider } from 'react-redux';
import store from './store';

// DOM返回APP组件,组件内容是一个Provider
// Provider 关联store后,将store提供给其内部的所有的组件
const App = (
<Provider store={store}>
<TodoList />
</Provider>
);

ReactDOM.render(App, document.getElementById('root'));

连接:

connect方法,前两个参数为连接的规则,最后的参数为本组件TodoList。

mapStateToProps:store里的数据、和组件里的数据关系关联

mapDispatchToProps:组件里props如何对store里的数据做修改、和store里的dispatch方法做关联。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//把store里的数据,映射到组件,变成组件里的props,将store里的inputValue,赋值给props的inputValue
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue
}
}

// 将store.dispatch 方法,挂载到 props
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue(e) {
const action = {
type: 'change_input_value',
value: e.target.value
};
dispatch(action)
}
}
}

// 谁和谁连接:本组件TodoList和store做连接
// 怎么做链接:规则在mapStateToProps中,把store里的数据,映射到组件,变成组件里的props

// TodoList和store关联,store的数据映射到组件的props上;想修改store,通过store的props。
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
// 实际上:todoList是一个UI组件,connect把UI组件和业务逻辑(数据、派发)结合,返回的结果为一个容器组件。
// 导出的内容就是connect的执行结果:容器组件

###